﻿using System;
using System.Reflection.Emit;
using Sigil.Impl;

namespace Sigil
{
	public partial class Emit<DelegateType>
	{
		/// <summary>
		/// Expects a pointer, an initialization value, and a count on the stack.  Pops all three.
		///
		/// Writes the initialization value to count bytes at the passed pointer.
		/// </summary>
		public Emit<DelegateType> InitializeBlock(Boolean isVolatile = false, Int32? unaligned = null)
		{
			if (unaligned.HasValue && (unaligned != 1 && unaligned != 2 && unaligned != 4))
			{
				throw new ArgumentException("unaligned must be null, 1, 2, or 4");
			}

			if (!AllowsUnverifiableCIL)
			{
				FailUnverifiable("InitializeBlock");
			}

			if (isVolatile)
			{
				UpdateState(OpCodes.Volatile, Wrap(StackTransition.None(), "InitializeBlock"));
			}

			if (unaligned.HasValue)
			{
				UpdateState(OpCodes.Unaligned, (Byte)unaligned.Value, Wrap(StackTransition.None(), "InitializeBlock"));
			}

			var transition =
					new[] {
                    new StackTransition(new [] { typeof(Int32), typeof(Int32), typeof(NativeIntType) }, Type.EmptyTypes),
                    new StackTransition(new [] { typeof(Int32), typeof(NativeIntType), typeof(NativeIntType) }, Type.EmptyTypes),
                    new StackTransition(new [] { typeof(Int32), typeof(Int32), typeof(Byte*) }, Type.EmptyTypes),
                    new StackTransition(new [] { typeof(Int32), typeof(NativeIntType), typeof(Byte*) }, Type.EmptyTypes),
                    new StackTransition(new [] { typeof(Int32), typeof(Int32), typeof(Byte).MakeByRefType() }, Type.EmptyTypes),
                    new StackTransition(new [] { typeof(Int32), typeof(NativeIntType), typeof(Byte).MakeByRefType() }, Type.EmptyTypes)
                };

			UpdateState(OpCodes.Initblk, Wrap(transition, "InitializeBlock"));

			return this;
		}
	}
}